import Cesium from "../Ces/Cesium"
import { vsSource, fsSource } from "./WeIsolatedPointShaders"
import WeTextureUniform from "./WeTextureUniform"

class WeIsolatedPoint {
  private drawCommand
  private weTexturUniform: WeTextureUniform
  constructor(options) {
    this.weTexturUniform = new WeTextureUniform({
      sampler: Cesium.Sampler.NEAREST,
      animation: false,
      calculateNormal: false,
    })
    this.rebuild(options.context, options.weUniform, options.image, options.display)
  }

  updateData({
    context,
    image,
  }) {
    this.weTexturUniform.updateData(context, image)
  }

  rebuild(context, weUniform, image, display) {
    const { weTexturUniform } = this

    const width = weUniform.Properties.bufferSize
    const height = width
    const vertexNum = width * height

    const indices: number[] = []

    for (let r = 0; r < height * 2 - 1; r += 2) {
      for (let c = 0; c < width - 1; c++) {
        const a0 = r * width + c
        const b0 = a0 + width
        const c0 = a0 + 1
        const d0 = b0 + 1
        indices.push(a0, b0, c0)
        indices.push(b0, d0, c0)
      }
    }

    const geometry = new Cesium.Geometry({
      attributes: {
        position: new Cesium.GeometryAttribute({
          componentDatatype: Cesium.ComponentDatatype.BYTE,
          componentsPerAttribute: 1,
          values: new Uint8Array(vertexNum * 2),
        }),
      },
      indices,
    })
    const attributeLocations = Cesium.GeometryPipeline.createAttributeLocations(geometry);

    const vertexArray = Cesium.VertexArray.fromGeometry({
      context,
      geometry,
      attributeLocations,
      bufferUsage: Cesium.BufferUsage.STATIC_DRAW,
    })

    weTexturUniform.updateData(context, image)

    const uniformMap = {
      u_particlesTexture: () => weTexturUniform.baseTexture
    }

    weUniform.setupUniformMap(uniformMap)

    const vertexShaderSource = `
      ${weUniform.getSource(true)}
      ${display.getFragmentShaderSource(true, true, true)}
      ${vsSource}
    `

    const fragmentShaderSource = `
      ${weUniform.getSource(true)}
      ${fsSource}
    `

    const shaderProgram = Cesium.ShaderProgram.fromCache({
      context,
      vertexShaderSource,
      fragmentShaderSource,
      attributeLocations,
    })

    const renderState = Cesium.RenderState.fromCache({
      cull: {
        enabled: true,
        face: Cesium.CullFace.BACK,
      },
      depthTest: {
        enabled: true,
      },
      blending: Cesium.BlendingState.ALPHA_BLEND,
    })

    this.drawCommand = this.drawCommand?.shaderProgram.destroy()
    this.drawCommand = new Cesium.DrawCommand({
      vertexArray,
      shaderProgram,
      uniformMap,
      renderState,
      pass: Cesium.Pass.OPAQUE,
      primitiveType: Cesium.PrimitiveType.TRIANGLES
    })
  }

  update(frameState) {
    this.weTexturUniform.update(frameState)
    if (!this.weTexturUniform.ready) return
    frameState.commandList.push(this.drawCommand)
  }

  destroy() {
    this.weTexturUniform = this.weTexturUniform?.destroy()
    this.drawCommand = this.drawCommand?.shaderProgram.destroy()
    return Cesium.destroyObject(this)
  }
  isDestroyed() {
    return false
  }
}

export default WeIsolatedPoint
